﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Benchmark_System {


    /// <summary>
    /// 
    /// </summary>
    class Scheduler {
        public static Stopwatch time = new Stopwatch();
        internal Queue<Job> ShortQueue = new Queue<Job>();
        internal Queue<Job> LongQueue = new Queue<Job>();
        internal Queue<Job> VeryLongQueue = new Queue<Job>();

        //HashSet to keep track of removed jobs
        internal HashSet<Job> RemovedJobsHashSet = new HashSet<Job>();

        //tracks the job count
        internal int counter = 0;

        internal static volatile int CpuUsage = 0;

        /// <summary>
        /// 
        /// </summary>
        public Scheduler() {
            time.Start();
        }

        /// <summary>
        /// Push a job to the queue it belongs in
        /// </summary>
        /// <param name="job">the new job</param>
        internal void AddJob(Job job) {
            if (job != null) {
                double expRun = job.ExpectedRuntime;
                //job.TimeStamp = (long)((DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalMilliseconds + 0.5);
                if (expRun <= 0.5) {
                    //below 30
                    ShortQueue.Enqueue(job);
                }
                else if (0.5 < expRun && expRun <= 2) {
                    //between 30 and 120 mins
                    LongQueue.Enqueue(job);
                }
                else if (expRun > 2) {
                    //above 30
                    VeryLongQueue.Enqueue(job);
                }
            }
        }

        /// <summary>
        /// Remove the latest element that were added
        /// </summary>
        /// <param name="job">the job to be removed</param>
        internal void RemoveJob(Job job) {
            RemovedJobsHashSet.Add(job);
        }

        /// <summary>
        /// Dequeue last job added
        /// </summary>
        /// <returns>job with highest count number</returns>
        internal Job PopJob() {
            Job jobA, jobB, jobC;
            jobA = (ShortQueue.Count > 0 ? ShortQueue.Dequeue() : null);
            jobB = (LongQueue.Count > 0 ? LongQueue.Dequeue() : null);
            jobC = (VeryLongQueue.Count > 0 ? VeryLongQueue.Dequeue() : null);

            long a, b, c;
            a = (jobA != null ? jobA.TimeStamp : 0);
            b = (jobB != null ? jobB.TimeStamp : 0);
            c = (jobC != null ? jobC.TimeStamp : 0);

            Job job;

            if (a > b && a > c) {
                job = jobA;
                AddJob(jobB);
                AddJob(jobC);
            }
            else if (b > a && b > c) {
                job = jobB;
                AddJob(jobA);
                AddJob(jobC);
            }
            else if (c > b && c > a) {
                job = jobC;
                AddJob(jobA);
                AddJob(jobB);
            }
            else {
                return null;
            }

            //If delayed twice
            if (job.delayed == 2) {
                Task<Job> waitThread = Task.Factory.StartNew<Job>(() => {
                    while (CpuUsage + job.Cpu > 30) {

                    }
                    return job;
                });
                waitThread.Wait();
                return waitThread.Result;
            }
            //if job is removed
            if (RemovedJobsHashSet.Contains(job)) {
                RemovedJobsHashSet.Remove(job);
                return PopJob();
            }
            //not enough cpu
            if (job.Cpu + CpuUsage > 30) {
                job.delayed++;
                AddJob(job);
                return PopJob();
            }
            //everything is fine
            CpuUsage = CpuUsage + job.Cpu;
            //Console.WriteLine("Owner: " + job.owner.name);
            return job;
        }
    }
}
